import Koa from 'koa'
// 加载配置文件
import bodyParser from 'koa-bodyparser'
import koaStatic from 'koa-static'
import cors from 'koa2-cors'
import path from 'path'
import valid from './middleware/valid.middleware'
import { Plugin, PublicClass } from './lib/Plugin'
import { echo } from './tool/echo'; // 控制台输出
import autoLoadingPlug from './tool/autoLoadingPlug'

import { InterfaceOption, joinOption } from './tool/option'
import processMiddleware from './middleware/processMiddleware'

import AccessToken from './lib/AccessToken'
import Media from './lib/Media';
import { Material } from './lib/Material';
import { Menu } from './lib/Menu';
import Custom from './lib/Custom';
import { router } from './router/index'
import { api } from './router/api'
import { User } from './lib/User';
import { Tag } from './lib/Tag';
import { Qrcode } from './lib/Qrcode';
import { Store } from './lib/Store';
import { Mass } from './lib/Mass';
import { Template } from './lib/Template';
export { Tmp } from './tool/Tmp'
export { Downloader } from './tool/Downloader'


class WX {
  /** koa 实例 */
  public koa: Koa = new Koa();
  /** 访问令牌的实例（对象） */
  public accessToken: AccessToken | undefined
  /** 访问令牌（字符串） */
  get access_token(): string { return this.accessToken?.toString() ?? '' }


  /** 临时素材 */
  public media: Media
  /** 永久素材 */
  public material: Material
  /** 自定义菜单 */
  public menu: Menu
  /** 客服 */
  public custom: Custom
  /** 用户管理 */
  public user: User
  /** 标签管理 */
  public tag: Tag
  /** 二维码工具 */
  public qrcode: Qrcode
  /** 群发 */
  public mass: Mass
  /** 模板消息 */
  public template: Template


  /** 插件数组 */
  public plugins: PublicClass[] = [];
  /** 构造函数参数，被使用的参数 */
  public option: InterfaceOption;
  /** 构造函数参数，通过参数传入的原始数据 */
  public readonly codeOption: InterfaceOption;
  /** 构造函数 */
  constructor(option: InterfaceOption) {
    this.codeOption = option;


    this.option = joinOption(this.codeOption);
    
    // 判断是否填写仓库目录
    Store.path = this.codeOption?.store_path as string;

    // 将自己挂载到koa实例上
    this.koa.context.wx = this
    // 判断是否开启访问令牌模块
    if (this.option.appid && this.option.secret) {
      this.accessToken = new AccessToken(this.option.appid, this.option.secret)
    }

    // 判断是否填写插件目录
    autoLoadingPlug(this.codeOption?.plugin_path, this)

    /** 临时素材管理 */
    this.media = new Media(this)
    /** 永久素材管理 */
    this.material = new Material(this)
    /** 自定义菜单 */
    this.menu = new Menu(this)
    /** 客服 */
    this.custom = new Custom(this);
    /** 用户管理 */
    this.user = new User(this);
    /** 标签管理 */
    this.tag = new Tag(this)
    /** 二维码工具 */
    this.qrcode = new Qrcode(this)
    /** 群发 */
    this.mass = new Mass(this);
    /** 模板消息 */
    this.template = new Template(this);
    /** 允许跨域 */
    this.koa.use(cors())
    /** 静态资源服务器 */
    this.koa.use(koaStatic(path.join(__dirname, '../', 'public')))
    // 解析请求体
    this.koa.use(bodyParser({
      enableTypes: ['json', 'xml', 'form', 'text'],
      formLimit: '10mb',
      extendTypes: {
        text: ['application/javascript'] // will parse application/x-javascript type body as a JSON string
      }
    }))

    // 请求/响应日志
    this.koa.use(async (ctx, next) => {
      const start_time = Date.now()
      echo(`>>> [${ctx.request.path}] ${JSON.stringify(ctx.request.body)}`.substr(0, 200))
      await next();
      echo(`<<< [${Date.now() - start_time}ms][${ctx.status}] ${ctx.body} `.substr(0, 200))
    })

    // 添加接入认证插件(只处理 GET 且携带 echostr 参数)
    this.koa.use(valid(this.option.token))
    // 路由
    this.koa.use(router.routes())
    // 插件处理机制
    this.koa.use(processMiddleware(this))
    // 启动
    this.koa.listen(this.option.port).address();

    echo(`服务已启动和运行,地址是:http://localhost:${this.option.port}`)

  }
  /**
   * 添加这个插件到插件列表
   * @param plugin 插件类 或者 一个由插件类组成的数组
   * @returns 返回自己
   */
  public use(plugin: PublicClass | PublicClass[]): WX {
    if (plugin instanceof Array) {
      // 触发使用事件
      plugin.forEach(e => e.onUse(this))
      this.plugins = this.plugins.concat(plugin);
    } else {
      // 触发使用事件
      plugin.onUse(this);
      this.plugins.push(plugin);
    }
    // 对插件进行排序
    this.sort_public();
    return this;
  }

  /** 对插件进行排序，按优先级 */
  private sort_public() {
    // 这里采用的降序排序，如果升序则使用 p1 - p2
    this.plugins.sort((p1, p2) => p2.priority - p1.priority)
  }
}


export { WX, Plugin, Store, router, api }